/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://git.oschina.net/cblock/embedme
 * Copyright 2014~2020 @ ShenZhen ,China
*******************************************************************************/
#ifndef __SOCKET_H__
#define __SOCKET_H__

#include "BaseType.h"
#include "Thread.h"
#include "ThreadUtil.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <iostream>
#include <vector>

namespace libemb{

#define UDP_PACKET_LEN_MAX	1472	/* UDP包最大长度 */

/** 定义socket的可选项 */
enum SOCKET_OPTION_E
{
    SOCKET_OPTION_CASTTYPE, /* 发送方式 */
    SOCKET_OPTION_RCVBUF,	/* 接收窗口大小 */
    SOCKET_OPTION_SNDBUF,	/* 发送窗口大小 */
    SOCKET_OPTION_CANBTR,	/* CAN 波特率 */
    SOCKET_OPTION_UNKNOWN=0xFF,
};

/** 定义socket的类型 */
enum SOCKET_TYPE_E
{
    SOCKET_TYPE_BROADCAST,  /**< 广播 */
    SOCKET_TYPE_GROUPCAST,  /**< 组播 */
    SOCKET_TYPE_MULTICAST,  /**< 多播 */
};


/** 定义tcp连接状态 */
enum TCP_LINK_E
{
    TCP_LINK_DISCONNECT,    /**< 断开状态 */
    TCP_LINK_CONNECTED,     /**< 连接状态 */
};


/**
 *  \file   Socket.h   
 *  \class  Socket
 *  \brief  Socket抽象基类	
 */

class Socket{
public:
    Socket();
    virtual ~Socket();
	virtual bool open(std::string localAddr="",uint16 localPort=0)=0;
    virtual bool close();
	virtual int readData(char* buf, int len);
	virtual int writeData(const char* buf ,int len);
    virtual int peekData(char *buf, int len, int usTimeout=-1);
    virtual int recvData(char *buf, int len, int usTimeout=-1);
    virtual int sendData(const char *buf, int len,int usTimeout=-1);
    virtual int setOption(int socketOpt, int value);
    virtual int getOption(int socketOpt);
	virtual bool setConnection(std::string peerAddr,uint16 peerPort);
	virtual bool getConnection(std::string& peerAddr,uint16& peerPort);
    bool isAlive();
	int fd();
	bool fdopen(int fd);
protected:
	bool bindPort(uint16 localPort, std::string localAddr="");
protected:
	std::string m_peerAddr{""};
	uint16 m_peerPort{0};
    int m_sockfd{-1};
    struct sockaddr_in m_localSockAddr;
	Mutex m_rMutex;
	Mutex m_wMutex;
};

/**
 *  \file   Socket.h   
 *  \class  UdpSocket
 *  \brief  UdpSocket类	
 */

class UdpSocket:public Socket{
public:
    UdpSocket();
    virtual ~UdpSocket();
    bool open(std::string localAddr="",uint16 localPort=0);
    bool close();
	int readData(char* buf, int len);
	int writeData(const char* buf ,int len);
    int recvData(char* buf,int len,int usTimeout=-1);
    int sendData(const char* buf,int len, int usTimeout=-1);    
};

/**
 *  \file   Socket.h   
 *  \class  TcpSocket
 *  \brief  TcpSocket类	
 */

class TcpSocket:public Socket{
public:
    TcpSocket();
    virtual ~TcpSocket();
    virtual bool open(std::string localAddr="",uint16 localPort=0);
    virtual bool close();
    virtual bool listenConnection(int maxpend);                        /* 监听连接 */
    virtual bool acceptConnection(TcpSocket& newSocket);               /* 接受连接 */
    virtual bool setConnection(std::string peerAddr,uint16 peerPort);  /* 连接对端 */
};

/**
 *  \file   Socket.h   
 *  \class  LocalTcpSocket
 *  \brief  LocalTcpSocket类	
 */
class LocalTcpSocket:public TcpSocket{
public:
    /**************************************************
     * LocalSocket在Android中Native端使用时需分配权限,这样 
     * App才可以使用该socket. 
     * init.rc中增加： 
     * service socket_test /system/native/socket_test 
     *         class main
     *         socket_name steam 600 system system
     *************************************************/
    LocalTcpSocket();
    virtual ~LocalTcpSocket();
    bool open(std::string localSocketName="",uint16 localPort=0);
    bool acceptConnection(TcpSocket& newSocket); /* 接受连接 */
    bool setConnection(std::string peerAddr,uint16 peerPort);         /* 连接本地连接 */
    
private:
	std::string m_socketName{""};
	std::string m_peerName{""};
};

/**
 *  \file   Socket.h   
 *  \class  UdpServer
 *  \brief  UdpServer类	
 */
class UdpServer:public Runnable{
public:
    UdpServer();
    virtual ~UdpServer();
    bool startServer(std::string serverIP,uint16 serverPort);
	void stopServer();
    virtual void onNewDatagram(UdpSocket& udpSocket,char* data, int len)=0;
private:
    void run();	
private:
    UdpSocket m_serverSocket;
	bool m_stopFlag{false};
};


/**
 *  \file   Socket.h   
 *  \class  TcpServer
 *  \brief  TcpServer类	
 */
class TcpServer:public Runnable{
public:
    TcpServer();
    virtual ~TcpServer();
    virtual bool startServer(std::string serverIP,uint16 serverPort,int maxPendings=1);
	void stopServer();
    virtual void onNewConnection(std::unique_ptr<TcpSocket> client)=0;
private:
    void run();
protected:
	bool m_stopFlag{false};
    std::unique_ptr<TcpSocket> m_serverSocket;
};

/**
 *  \file   Socket.h   
 *  \class  LocalTcpServer
 *  \brief  LocalTcpServer	
 */
class LocalTcpServer:public TcpServer{
public:
    LocalTcpServer();
    virtual ~LocalTcpServer();
	bool startServer(std::string serverName,uint16 serverPort,int maxPendings=1);
private:
    void run();
};

class SocketPair{
public:
	enum{
	PAIRFD_READ=0,
	PAIRFD_WRITE=1,
	}PAIRFD_TYPE_E;	
public:
    SocketPair();
    ~SocketPair();
    bool createPair();
    int fd(int pairType);
    int recvData(char* buf,int len,int usTimeout=-1);
    int sendData(const char* buf,int len, int usTimeout=-1);
private:
    int m_fd[2]{-1,-1};
};

/* 帧格式 */
enum CAN_FF_E
{
	CAN_FF_STD=0,/* 标准帧 */
	CAN_FF_EXT	/* 扩展帧 */
};

enum CAN_FT_E
{
	CAN_FT_DATA=0,	/* 数据帧 */
	CAN_FT_REMOTE	/* 远程帧 */
};

enum CAN_FE_E
{
	CAN_FE_NONE=0,	/* 无错误 */
	CAN_FE_ERR		/* 错误消息 */
};

class SocketCAN;
class CANFrame{
public:
	CANFrame();
	CANFrame(uint32 id,char* data,uint8 len,uint8 format=CAN_FF_STD);
	~CANFrame();
	uint8 format();
	uint8 type();
	uint8 error();
	uint32 id();
	uint8 dataLen();
	char* data();
private:
	friend class SocketCAN;
	struct can_frame m_frame;
};

/******************************************************************************
 * SocketCAN
 * 仅实现数据收发功能,对于CAN接口的配置请使用libsocketcan开源库    .
 *****************************************************************************/
class SocketCAN:public Socket{
public:
	SocketCAN();
	virtual ~SocketCAN();
	std::string interface();
	bool open(std::string canName="",uint16 localPort=0);
    bool close();
	int recvFrame(CANFrame& canFrame,int usTimeout=-1);
	int sendFrame(CANFrame& canFrame,int usTimeout=-1);
	int readFrame(CANFrame& canFrame);
	int writeFrame(CANFrame& canFrame);
private:
    int recvData(char *buf, int len, int usTimeout=-1);
    int sendData(const char *data, int len,int usTimeout=-1);
	int peekData(char * buf, int len, int usTimeout){return RC_ERROR;}
	bool setConnection(std::string peerAddr,uint16 peerPort){return false;} 
	int setOption(int socketOpt, int value){return RC_ERROR;}
    int getOption(int socketOpt){return RC_ERROR;}
private:
	std::string m_interface{""};
};

}
#endif
